import BaseComp from "../Base/BaseComp";
import React from "react";
import {
    forEach,
    isArray,
    isBoolean,
    get,
    isEmpty,
    isFunction,
    isObject,
    filter,
    find,
    isPlainObject,
    pick, forIn, isEqual, indexOf, unionWith, findIndex, isString
} from "lodash-es";
import TableBase from "./TableBase";
import {isModernBrowser, isValEmpty, myFormatTime, recursiveMap} from "jh-utils";
import omit from "lodash-es/omit";
import {ComponentType, DataStatus} from "../Config";
import PropTypes from "prop-types";
import {compValuePreview, previewNumber} from "../Base/helper/compValuePreview";
import FieldCtrl from "../Config/FieldCtrl";

/**
 * 当前是否“现代浏览器”
 */
let isCurModernBrowser = isModernBrowser();

export default class TableComp extends BaseComp {

    static propTypes = {
        ...TableBase.propTypes,
        /**
         * 是否“多选”。默认 false
         */
        multi: PropTypes.bool,
        /**
         * 是否将“选中项”受控
         */
        selecting: PropTypes.bool,
    };

    static defaultProps = {
        multi: true // 默认多选
    };

    /**
     * @type {TableBase}
     */
    tableRef;

    /**
     * 已选中记录的 key 数组
     */
    selectedRowKeys = [];

    /**
     * 累积的已选中记录。以“记录的 key 字段”为 key，以“记录”为 value
     */
    selectedRows = {};

    /**
     * 获取表格数据
     * @param onlyChange {boolean} 是否只获取改变了的数据。默认 true
     * @return {undefined|{comboVal, compVal}|[]}
     */
    getAjaxData(onlyChange = true) {

        if (this.tableRef && isFunction(this.tableRef.getAjaxData)) {
            return this.tableRef.getAjaxData(onlyChange);
        }
    }

    /**
     * 获取不为空的数据
     * @param onlyChange {boolean} 是否只获取改变了的数据。默认 false
     * @return {*[]}
     */
    getDataNoEmpty(onlyChange = true) {

        if (this.tableRef && isFunction(this.tableRef.getDataNoEmpty)) {
            return this.tableRef.getDataNoEmpty(onlyChange);
        }
    }

    /**
     * 获取删除了的记录
     * @param fullRecord {boolean} 是否需要返回完整的记录。默认 false，只返回删除了的 id 数组
     * @return {[]}
     */
    getDeleted(fullRecord = false) {

        if (this.tableRef && isFunction(this.tableRef.getDeleted)) {
            return this.tableRef.getDeleted(fullRecord);
        }
    }

    /**
     * 获取选中的记录
     * @param fullRecord {boolean} 是否需要返回完整的记录。默认 true。否则只返回的 id 数组
     * @return {[]}
     */
    getSelected(fullRecord = true) {
        let reArr = [];

        if (!isEmpty(this.selectedRowKeys)) {
            const list = this.getAjaxData(false);
            forEach(this.selectedRowKeys, (rowKey) => {
                const tmpO = find(list, (lItem) => (lItem && lItem.key === rowKey));
                if (!isEmpty(tmpO)) {
                    if (fullRecord) {
                        reArr.push(tmpO);
                    } else {
                        reArr.push(tmpO.id);
                    }
                }
            });
        }
        return reArr;
    }

    /**
     * 设置表格数据
     * @param data
     * @param afterCb
     * @param reMountTable {boolean} 是否需要重载 Table。默认 false
     * @param isInit {boolean} 是否初始化，如果是，则添加 defaultRowCnt 相关逻辑
     */
    setData(data, afterCb, reMountTable = false, isInit = false) {

        if (this.tableRef && isFunction(this.tableRef.setData)) {
            return this.tableRef.setData(data, () => {
                // 如果要重载 Table，则清空当前已选项
                if (reMountTable && !isEmpty(this.selectedRowKeys)) {
                    this.changeRowSel([], []);
                }
                afterCb && afterCb();
            }, reMountTable, isInit);
        }
    }

    /**
     * 设置已选中的记录 key
     * @param selectedRowKeys {[string]} 已选中记录的 key 数组
     * @param afterCb
     */
    setSelectedKeys(selectedRowKeys, afterCb = null) {
        this.selectedRowKeys = selectedRowKeys;
        this.reRender(afterCb);
    }

    colRenders = {};

    /**
     * 设置“列渲染”
     * @param dataIndex
     * @param render
     */
    setColRender(dataIndex, render) {
        this.colRenders[dataIndex] = render;
    }


    /**
     * 聚焦到某个单元格
     * @param rowCol {{row: string, col: string}} 聚焦的行列。row：行的 key。col： 列的 dataIndex
     * @param editing {boolean} 是否正在编辑
     * @param afterCb
     */
    setFocusCell(rowCol, editing, afterCb) {

        if (this.tableRef && isFunction(this.tableRef.setFocusCell)) {
            this.tableRef.setFocusCell({row: '', col: ''});
            this.tableRef.setFocusCell(rowCol, editing, afterCb);
        }
    }

    /**
     * 将 data 数据排到前面，空行移到后面
     * @param data {[object]} 需要排到前面的数据列表
     * @param afterCb
     */
    refreshWithEmptyRow(data, afterCb) {
        if (this.tableRef && isFunction(this.tableRef.refreshWithEmptyRow)) {
            return this.tableRef.refreshWithEmptyRow(data, afterCb);
        }
    }


    /**
     * 重置“用于标识 表格有数据变化”的变量
     */
    resetModify() {

        if (this.tableRef && isFunction(this.tableRef.resetModify)) {
            return this.tableRef.resetModify();
        }
    }

    /**
     * 表格是否有变化
     * @return {boolean}
     */
    hadChanged() {

        if (this.tableRef && isFunction(this.tableRef.hadChanged)) {
            return this.tableRef.hadChanged();
        }
    }

    editRow(actKey) {
        // 如果是删除，且当前有勾选行，则调用批量删除行的方法
        if ('delete' === actKey && !isEmpty(this.selectedRowKeys) && isFunction(this.tableRef.deleteRows)) {
            this.tableRef.deleteRows(this.selectedRowKeys, () => {
                // 删除成功，则清空当前选中的数据
                this.setSelectedKeys([]);
            });

        } else if (isFunction(this.tableRef.editRow)) {
            return this.tableRef.editRow(actKey);
        }
    }

    /**
     * 选中项发生变化时的回调
     * @param selectedRowKeys
     * @param selectedRows
     */
    changeRowSel(selectedRowKeys, selectedRows) {
        // console.log('changeRowSel', selectedRowKeys, this.selectedRowKeys);
        // rowSelection.onChange
        const {rowSelection, selecting, multi} = this.getProps();
        const selRows = filter(selectedRows, (row) => !isEmpty(row));
        /**（>=antd@4.4.0，rowSelection.preserveSelectedRowKeys=true）**/
        let selected = this.selectedRowKeys.length <= selectedRowKeys.length;
        let changeRows = [];
        let changeRowKeys = [];

        // 如果是“选中操作”，则"selectedRowKeys, selectedRows"就包含了所有已选的数据
        if (selected) {
            this.selectedRowKeys = selectedRowKeys;

        } else {// 否则，将本次改变了的数据记录到“changeRows,changeRowKeys”
            // 如果是“取消选中”操作，将“取消了的记录”放到 changeRows
            this.selectedRowKeys = filter(this.selectedRowKeys, (key) => {
                // 如果 key 不在“当前剩余的已选中记录”中，即 key 被“取消选中”了
                if (indexOf(selectedRowKeys, key) === -1) {
                    changeRows.push({key, id: key}); // 将此次“取消选中的记录”放到 changeRows
                    changeRowKeys.push(key);
                    return false;
                }
                return true;
            });

        }
        // console.log('changeRowSel after',selected, this.selectedRowKeys);

        if (rowSelection && isFunction(rowSelection.onChange)) {
            let newSelKeys = rowSelection.onChange(
                selectedRowKeys,
                selRows,
                {selected, changeRows, changeRowKeys}
            );
            if (isArray(newSelKeys)) {
                this.selectedRowKeys = newSelKeys;
            }
        }
        // 将“选中”受控
        if (selecting) {
            this.reRender();
        }
    }

    /**
     * 用户手动选择/取消选择某行的回调
     * @param record
     * @param selected
     * @param selectedRows
     * @param nativeEvent
     */
    selectRow(record, selected, selectedRows, nativeEvent) {
        // console.log('selectRow', record, selected, selectedRows);
        // rowSelection.onSelect
        // 切换选定的行
        if (selected && record && record.key && isFunction(this.tableRef.setFocusRow)) {
            this.tableRef.setFocusRow(record.key)
        }
        const {rowSelection} = this.getProps();
        if (rowSelection && isFunction(rowSelection.onSelect)) {
            rowSelection.onSelect(record, selected, filter(selectedRows, (row) => (!isEmpty(row))), nativeEvent);
        }
    }

    reRenderTable(cb) {
        this.tableRef && this.tableRef.reRender(cb);
    }

    mainRender(context) {
        // console.log('this.selectedRowKeys', this.selectedRowKeys)
        const props = this.getProps();
        const {
            colsConf, l, r, columns, rowSelect, rowSelection, appins, belong = {},
            onRowProps, multi, selecting, cell
        } = props;

        const moreTableProps = {};
        let isConfCol = isArray(colsConf);
        let factCols = (isConfCol ? colsConf : columns) || [];
        let colLen = factCols.length;
        let isAllColHadWidth = true; // 标识是否所有列都设置了宽度

        // 获取字段权限 start
        let fieldCtrlObj = {};

        if (appins && !isEmpty(appins.viewConfig)) {
            const {body, fields} = appins.viewConfig;
            if (!isEmpty(fields)) {
                forEach(fields, (fieldConfig) => {
                    fieldCtrlObj[fieldConfig.fieldName] = fieldConfig.control;
                });
            }
        }
        // 获取字段权限 end

        const cols = recursiveMap(factCols, (col, index) => {
            // 列配置
            const {remark, name, floatNum, sum, reg, expression, format, align, colWidth, extend} = col;
            let width = (0 < colWidth && colWidth < 1) ? `${colWidth * 100}%` : (colWidth || col.width || 120);

            const reCol = {
                ...col,
                title: remark || col.title,
                dataIndex: name || col.dataIndex,
                key: col.key || name || col.dataIndex,
                align,
                width,
                fixed: isCurModernBrowser && col.fixed || '',
            };

            // 拼接字段名，用于区别为子表时，将子表的表字段拼接列字段
            let dataIndex = name || col.dataIndex;
            if (belong.body && !isEmpty(belong.bodyFieldName)) {
                dataIndex = `${belong.bodyFieldName}.${name || col.dataIndex}`;
            }

            // 获取当前列 字段权限
            let fieldCtrl;
            if (!isEmpty(fieldCtrlObj) && fieldCtrlObj.hasOwnProperty(dataIndex)) {
                fieldCtrl = fieldCtrlObj[dataIndex];
            }


            // 如果列属性名带有 '.'，或者为隐藏（3），说明是嵌套属性，则此列只能为“只读”
            if ((reCol.dataIndex && 0 < reCol.dataIndex.indexOf('.')) || FieldCtrl.HIDDEN === fieldCtrl) {
                reCol.editable = false;
            }

            // 处理列冻结 props.l、 props.r
            if (reCol.width && isCurModernBrowser) {

                if (l > 0 && index < l) {
                    reCol.fixed = 'left';
                }

                if (r > 0 && index >= (colLen - r)) {
                    reCol.fixed = 'right';
                }

            } else {
                isAllColHadWidth = false;
            }

            const newCol = {...reCol};

            reCol.render = (value, record, rowInd) => {

                // 设置如果列字段权限为 3 隐藏，则显示 '****'
                if (FieldCtrl.HIDDEN === fieldCtrl) {
                    return '*****';
                }

                if (isFunction(this.colRenders[newCol.dataIndex])) {
                    return this.colRenders[newCol.dataIndex](value, record, rowInd, {col: newCol, belong});
                }

                if (isFunction(newCol.render)) {
                    return newCol.render(value, record, rowInd, {col: newCol, belong});
                }

                let showContent;
                let fValue = value;

                if (appins && isFunction(appins.renderCol)) {
                    showContent = appins.renderCol(value, record, rowInd, {col: newCol, belong});

                    if ('undefined' !== typeof showContent && false !== showContent) {
                        return showContent;
                    }
                }

                if (0 < reCol.dataIndex.indexOf('.')) {
                    showContent = get(record, reCol.dataIndex);
                    fValue = showContent;
                } else {
                    showContent = fValue;
                }

                if (record.IS_SUM) {

                    if (ComponentType.NUMBER_INPUT === newCol.componentType) {
                        let v = !isValEmpty(fValue) ? previewNumber(fValue, floatNum, format) : showContent;
                        return (
                            <div title={v || ''} style={{
                                whiteSpace: 'nowrap',
                                // textAlign: 'right',
                                overflow: 'hidden',
                                textOverflow: 'ellipsis'
                            }}>
                                {v}
                            </div>
                        )
                    } else {
                        return showContent;
                    }
                }

                // 如果为自定义扩展字段
                if (extend) {
                    let {extJSON} = record;
                    if (isString(extJSON)) {
                        try {
                            let extJSONObj = JSON.parse(extJSON);
                            if (isObject(extJSONObj) && !isEmpty(extJSONObj) && extJSONObj.hasOwnProperty(name)) {
                                fValue = extJSONObj[name];
                            }
                        } catch (e) {

                        }
                    }
                }

                showContent = compValuePreview(newCol.componentType, {
                    ...newCol.componentType === 'TAG_EDITOR' && {appins} || {},
                    value: fValue, floatNum, format,
                    dataIndex: newCol.dataIndex,
                    selector: newCol.selector,
                    formatMsgByCn: this.formatMsgByCn.bind(this),
                    col: newCol,
                    record
                });

                return showContent;
            };

            return reCol;
        });

        if (isAllColHadWidth && colLen > 0) {
            let colIndWithAutoWidth = r > 0 ? colLen - r - 1 : colLen - 1;
            if (cols[colIndWithAutoWidth]) {
                (cols[colIndWithAutoWidth]).width = '';
            }
        }

        // 左侧 checkbox
        if (rowSelect) {
            moreTableProps.rowSelection = {
                type: multi ? 'checkbox' : 'radio',
                fixed: isCurModernBrowser && true,
                columnWidth: 50,
                preserveSelectedRowKeys: true, // 当数据被删除时仍然保留选项的 key。（>=antd@4.4.0）
                ...(rowSelection || {}),
                onChange: this.changeRowSel.bind(this),
                onSelect: this.selectRow.bind(this),
            };

            // 如果是“单选”，则点击行时，可进行“选中”
            if (false === multi) {
                moreTableProps.onRowProps = {
                    ...onRowProps,
                    onClick: (e, curRecord) => {
                        this.changeRowSel([curRecord.key], [curRecord]);

                        if (onRowProps && isFunction(onRowProps.onClick)) {
                            onRowProps.onClick(e, curRecord);
                        }
                    }
                };
            }

            // 将“选中”受控
            if (selecting) {
                moreTableProps.rowSelection.selectedRowKeys = this.selectedRowKeys;
            }
        }

        return (
            <TableBase
                {...omit(props, ['rowSelection'])}
                columns={cols}
                {...moreTableProps}
                onRowUpdate={(arg) => {
                    // 如果是“删除行”，则在删除之后，清空当前选中项
                    if ('delete' === arg.type) {
                        this.changeRowSel([], []);
                    }

                    const onRowUpdate = this.getPropsByName('onRowUpdate');
                    if (isFunction(onRowUpdate)) {
                        return onRowUpdate(arg);
                    }
                }}
                onRef={(ref) => {
                    this.tableRef = ref;
                }}
            />
        )
    }
}